package tester;

import java.io.IOException;
import java.io.File;
import compiler.Compiler;

/**
 * Test a person for a single problem.
 * Make sure the person finished the problem.
 */
public class PersonProblemTester {
  public final Person person;
  public final Problem problem;
  public final String workDir;
  public final String programDir;

  public PersonProblemTester(Person person, Problem problem, String workDir) {
    this.workDir = workDir;
    this.person = person;
    this.problem = problem;
    programDir = person.baseDir + File.separator + problem.name;
  }

  public void runTest() {
    MyUIManager.updateMainTableFocus(person, problem);
    MessageOutput.println('[' + person.name + '.' + problem.name + "]: ");
    if (!getReadyForTest(person, problem)) {
      Grade grade = person.stat.get(problem.name);
      grade.clear();
      grade.setNotSubmitted();
      MessageOutput.println("Not Submitted.");
      return;
    }
    for (int i = 0; i < problem.casesCount; i++) {
      SingleCaseTester sct = new SingleCaseTester(
          person, problem,
          programDir + File.separator + problem.executableName, workDir,
          problem.getCaseInput(i), problem.getCaseOutput(i),
          problem.timeout, problem.comparator);
      TestCaseResult tcr = null;
      MyUIManager.setTitle(Config.PROGRAM_TITLE + " [" +
          person.name + " : " + problem.name + " #" + i + "]");
      try {
        tcr = sct.runTest();
      } catch (InternalErrorException e) {
        tcr = new TestCaseResult(TestCaseResult.ExitCode.ERROR, 0, 0);
      }
      MyUIManager.repaintAll();
      MessageOutput.println("#" + i + ": " + TestCaseResult.getExitCodeShortcut(tcr));
      person.addTestCaseResult(problem.name, tcr);
    }
    person.updateTotalScore();
    MyUIManager.setTitle(Config.PROGRAM_TITLE);
    MessageOutput.println();
  }

  private boolean getReadyForTest(Person person, Problem problem) {
    if (!person.finished(problem.name)) return false;
    Grade grade = person.stat.get(problem.name);
    String fileName = person.baseDir + File.separator + problem.name +
        File.separator + problem.name;
    try {
      MessageOutput.println("Compiling " + problem.name + " for " + person.name);
      if (person.isCSourceSubmitted(problem)) {
        Compiler.compile(new File(fileName + ".c"));
      } else {
        Compiler.compile(new File(fileName + ".cpp"));
      }
      // if compilation failed, change status to not submitted.
      if (!person.isExeSubmitted(problem)) {
        grade.setNotSubmitted();
        return false;
      }
    } catch (IOException e) {
      grade.setNotSubmitted();
      return false;
    }
    // when submitted, we clear the grades before testing.
    grade.setSubmitted();
    grade.clear();
    return true;
  }
}
